import { join } from 'path'
import { load } from 'protobufjs'
import { ErrorMessage, ErrorPayload, isErrorMessage, isRequestMessage, isResponseMessage, isSendToMessage, isSendToRoomMessage, Message, MessageBuffer, MessageType, RequestMessage, RequestPayload, ResponseMessage, ResponsePayload, SendToPayload, SendToRoomPayload } from '@core/types'
export function loadProto() {
    const root = join(__dirname, '../core.proto')
    return load(root)
}
export function createTypeBuffer(type: protobuf.Type, payload: any) {
    const errMsg = type.verify(payload);
    if (errMsg) {
        console.log({ payload })
        throw Error(`Failed to verify message: ${errMsg}`);
    }
    const message = type.create(payload);
    const buffer = type.encode(message).finish();
    return Buffer.from(buffer);
}
export function requestToBuffer(root: protobuf.Root, payload: RequestPayload): Buffer {
    const Message = root.lookupType('Message')
    const RequestPayload = root.lookupType('RequestPayload')
    return createTypeBuffer(Message, { type: MessageType.REQUEST, payload: createTypeBuffer(RequestPayload, payload) });
}

export function requestToBufferV2(root: protobuf.Root, payload: Buffer): Buffer {
    const Message = root.lookupType('Message')
    const RequestPayload = root.lookupType('RequestPayload')
    return createTypeBuffer(Message, { type: MessageType.REQUEST, payload: createTypeBuffer(RequestPayload, { data: payload }) });
}

export function requestFromBuffer(root: protobuf.Root, payload: Buffer): RequestMessage {
    const Message = root.lookupType('Message')
    const req: MessageBuffer = Message.decode(payload) as any;
    if (isRequestMessage(req)) {
        const RequestPayload = root.lookupType('RequestPayload')
        const payload: RequestPayload = RequestPayload.decode(req.payload) as any;
        return {
            type: req.type,
            payload: payload
        }
    }
    console.log(req)
    throw new Error(`requestFromBuffer error`)
}
export function responseToBuffer(root: protobuf.Root, payload: ResponsePayload | ErrorPayload): Buffer {
    const Message = root.lookupType('Message')
    const ResponsePayload = root.lookupType('ResponsePayload')
    return createTypeBuffer(Message, { type: MessageType.RESPONSE, payload: createTypeBuffer(ResponsePayload, payload) });
}
export function sendToBuffer(root: protobuf.Root, payload: SendToPayload) {
    const Message = root.lookupType('Message')
    const SendToPayload = root.lookupType('SendToPayload')
    return createTypeBuffer(Message, { type: MessageType.SENDTO, payload: createTypeBuffer(SendToPayload, payload) });
}

export function sendToRoomBuffer(root: protobuf.Root, payload: SendToRoomPayload) {
    const Message = root.lookupType('Message')
    const SendToRoomPayload = root.lookupType('SendToRoomPayload')
    return createTypeBuffer(Message, { type: MessageType.SENDTOROOM, payload: createTypeBuffer(SendToRoomPayload, payload) });
}

export function errorToBuffer(root: protobuf.Root, payload: ErrorPayload): Buffer {
    const Message = root.lookupType('Message')
    const ErrorPayload = root.lookupType('ErrorPayload')
    return createTypeBuffer(Message, { type: MessageType.ERROR, payload: createTypeBuffer(ErrorPayload, payload) });
}
export function responseFromBuffer(root: protobuf.Root, payload: Buffer): ResponseMessage | ErrorMessage | Message<SendToPayload> | Message<SendToRoomPayload> {
    const Message = root.lookupType('Message')
    const req: MessageBuffer = Message.decode(payload) as any;
    if (isSendToMessage(req)) {
        const SendToPayload = root.lookupType('SendToPayload')
        const payload: SendToPayload = SendToPayload.decode(req.payload) as any;
        return {
            type: req.type,
            payload: payload
        }
    }
    if (isSendToRoomMessage(req)) {
        const SendToRoomPayload = root.lookupType('SendToRoomPayload')
        const payload: SendToPayload = SendToRoomPayload.decode(req.payload) as any;
        return {
            type: req.type,
            payload: payload
        }
    }
    if (isSendToRoomMessage(req)) {
        const SendToPayload = root.lookupType('SendToPayload')
        const payload: SendToPayload = SendToPayload.decode(req.payload) as any;
        return {
            type: req.type,
            payload: payload
        }
    }
    if (isResponseMessage(req)) {
        const ResponsePayload = root.lookupType('ResponsePayload')
        const payload: ResponsePayload = ResponsePayload.decode(req.payload) as any;
        return {
            type: req.type,
            payload: payload
        }
    }
    if (isErrorMessage(req)) {
        const ErrorPayload = root.lookupType('ErrorPayload')
        const payload: ErrorPayload = ErrorPayload.decode(req.payload) as any;
        return {
            type: req.type,
            payload: payload
        }
    }
    throw new Error(`responseFromBuffer error`)
}